
#include <BPainter>
#include <BCursor>
#include <BFont>
#include <BMouseEvent>
#include <BKeyEvent>
#include <BScrollBar>

#include <BTreeWidget>
#include "member_BScrollArea.h"
#include "member_BTreeWidget.h"
#include "member_BTreeItem.h"
#include "member_BWidget.h"
#include "member_BStyle.h"

using namespace BWE;

#define member					(*(member_BTreeWidget*)_ptr)
#define member_allocate()		_ptr = new member_BTreeWidget(this)
#define member_release()		delete (member_BTreeWidget*)_ptr

BTreeWidget::BTreeWidget(BWidget* parent) : BScrollArea(parent)
{
	member_allocate();
	this->setAreaPolicy(Policy_Growing, Policy_Preferred);
}
BTreeWidget::BTreeWidget(const BString& title, BWidget* parent) : BScrollArea(title, parent)
{
	member_allocate();
	this->setAreaPolicy(Policy_Growing, Policy_Preferred);
}
BTreeWidget::~BTreeWidget()
{
	member_release();
}

void BTreeWidget::expandAll()
{
	if (member.items.size())
	{
		for (int i = 0; i < member.items.size(); i++)
		{
			BTreeItem* item = member.items[i];
			member.expandAll(item);
			member.freshWidget(item, true);
		}
		member.dirty = true;
		this->fresh();
	}
}
void BTreeWidget::shrinkAll()
{
	if (member.items.size())
	{
		for (int i = 0; i < member.items.size(); i++)
		{
			BTreeItem* item = member.items[i];
			member.shrinkAll(item);
			member.freshWidget(item, false);
		}
		member.dirty = true;
		this->fresh();
	}
}

void BTreeWidget::expand(BTreeItem* item)
{
	if (item && item_member(item)->tree == this && !item_member(item)->expanded)
	{
		item_member(item)->expanded = true;
		member.freshWidget(item, true);
		this->emit(Signal_ItemExpanded, item);
		member.dirty = true;
		this->fresh();
	}
}
void BTreeWidget::shrink(BTreeItem* item)
{
	if (item && item_member(item)->tree == this && item_member(item)->expanded)
	{
		item_member(item)->expanded = false;
		member.freshWidget(item, false);
		this->emit(Signal_ItemShrinked, item);
		member.dirty = true;
		this->fresh();
	}
}

void BTreeWidget::setSelectMode(SelectMode selectMode)
{
	if (member.selectMode != selectMode)
	{
		member.selectMode = selectMode;
		this->clearSelection();
	}
}
SelectMode BTreeWidget::selectMode() const
{
	return member.selectMode;
}

void BTreeWidget::setArrowVisible(bool arrowVisible)
{
	if (member.arrowVisible != arrowVisible)
	{
		member.arrowVisible = arrowVisible;
		member.dirty = true;
		this->fresh();
	}
}
bool BTreeWidget::arrowVisible() const
{
	return member.arrowVisible;
}

void BTreeWidget::setArrowSize(const BSize& arrowSize)
{
	if (member.arrowSize != arrowSize)
	{
		member.arrowSize = arrowSize;
		this->fresh();
	}
}
const BSize& BTreeWidget::arrowSize() const
{
	return member.arrowSize;
}

void BTreeWidget::setIndent(int indent)
{
	if (member.indent != indent)
	{
		member.indent = indent;
		member.dirty = true;
		this->fresh();
	}
}
int BTreeWidget::indent() const
{
	return member.indent;
}

void BTreeWidget::setItemSpacing(int itemSpacing)
{
	if (member.itemSpacing != itemSpacing)
	{
		member.itemSpacing = itemSpacing;
		this->fresh();
	}
}
int BTreeWidget::itemSpacing() const
{
	return member.itemSpacing;
}

void BTreeWidget::setItemPolicy(Policy itemPolicy)
{
	if (member.itemPolicy != itemPolicy)
	{
		member.itemPolicy = itemPolicy;
		member.dirty = true;
		this->fresh();
	}
}
Policy BTreeWidget::itemPolicy() const
{
	return member.itemPolicy;
}

bool BTreeWidget::addItem(BTreeItem* item)
{
	if (!item)
		return false;
	if (item_member(item)->tree == this)
	{
		BHolder<BTreeItem> holder(item);
		if (item_member(item)->parent)
			item_member(item)->parent->removeChild(item);
		this->emit(Signal_ItemInserted, item);
		return true;
	}
	member.items.append(item);
	if (item_member(item)->tree)
		item_member(item)->tree->removeItem(item);
	if (item_member(item)->parent)
		item_member(item)->parent->removeChild(item);
	item_member(item)->attach(this);
	this->emit(Signal_ItemInserted, item);
	member.dirty = true;
	this->fresh();
	return true;
}
BTreeItem* BTreeWidget::addItem(const BString& text)
{
	BTreeItemHolder item = new BTreeItem(text);
	if (addItem(item))
		return item;
	return 0;
}
BTreeItem* BTreeWidget::addItem(Graph graph, const BString& text, Form form)
{
	BTreeItem* item = new BTreeItem(graph, text, form);
	this->addItem(item);
	return item;
}
BTreeItem* BTreeWidget::addItem(BIcon* icon, const BString& text, Form form)
{
	BTreeItem* item = new BTreeItem(icon, text, form);
	this->addItem(item);
	return item;
}
BTreeItem* BTreeWidget::addItem(BImage* image, const BString& text, Form form)
{
	BTreeItem* item = new BTreeItem(image, text, form);
	this->addItem(item);
	return item;
}
BTreeItem* BTreeWidget::addItem(BWidget* widget, const BString& text, Form form)
{
	BTreeItem* item = new BTreeItem(widget, text, form);
	this->addItem(item);
	return item;
}

bool BTreeWidget::removeItem(int index)
{
	BTreeItem* item = member.items(index);
	return removeItem(item);
}
bool BTreeWidget::removeItem(BTreeItem* item)
{
	if (!item)
		return false;
	if (item_member(item)->tree != this)
		return false;
	if (member.selectedItems.remove(item))
	{
		item_member(item)->selected = false;
		this->emit(Signal_ItemSelected, item);
	}
	item_member(item)->detach(this);
	if (BTreeItem* parent = item_member(item)->parent)
	{
		parent->removeChild(item);
	}
	else
	{
		member.items.remove(item);
	}
	member.dirty = true;
	this->fresh();
	return true;
}
bool BTreeWidget::removeItem(const BString& text)
{
	if (BTreeItem* item = this->item(text))
		return removeItem(item);
	return false;
}

void BTreeWidget::clearItems()
{
	if (member.items.size())
	{
		member.hoveredArrow = false;
		member.hoveredItem = 0;
		member.visualItems.clear();
		if (member.selectedItems.size())
		{
			while (BTreeItem* item = member.selectedItems.last())
			{
				member.selectedItems -= item;
				item_member(item)->selected = false;
				this->emit(Signal_ItemSelected, item);
			}
			emit(Signal_SelectionChanged, 0);
		}
		while (BTreeItem* item = member.items.last())
		{
			item_member(item)->detach(this);
			member.items.remove(item);
		}
		this->setAreaSize(0, 0);
		this->fresh();
	}
}

bool BTreeWidget::containItem(const BTreeItem* item) const
{
	if (!item)
		return false;
	for (int i = 0; i < member.items.size(); i++)
	{
		BTreeItem* topItem = member.items[i];
		if (topItem == item)
			return true;
		if (topItem->contain(item))
			return true;
	}
	return false;
}
bool BTreeWidget::containItem(const BString& text) const
{
	for (int i = 0; i < member.items.size(); i++)
	{
		BTreeItem* item = member.items[i];
		if (item->text() == text)
			return true;
		if (item->findByText(text))
			return true;
	}
	return false;
}

int BTreeWidget::itemIndex(const BTreeItem* item) const
{
	if (BTreeItem* parent = item_member(item)->parent)
	{
		BArray<BTreeItemHolder>& children = item_member(parent)->children;
		return children.find(item);
	}
	return member.items.find(item);
}
int BTreeWidget::itemIndex(const BString& text) const
{
	for (int i = 0; i < member.items.size(); i++)
	{
		BTreeItem* item = member.items[i];
		if (item->text() == text)
			return i;
	}
	return -1;
}

bool BTreeWidget::replaceItem(BTreeItem* item, BTreeItem* newItem)
{
	if (!item)
		return false;
	if (item_member(item)->tree != this)
		return false;
	if (member.selectedItems.remove(item))
	{
		item_member(item)->selected = false;
		this->emit(Signal_ItemSelected, item);
	}
	if (BTreeItem* parent = item_member(item)->parent)
	{
		return parent->replaceChild(item, newItem);
	}

	BHolder<BTreeItem> holder(item);
	item_member(item)->detach(this);
	if (newItem)
	{
		int index = member.items.find(item);
		member.items[index] = newItem;

		if (item_member(newItem)->tree)
			item_member(newItem)->tree->removeItem(newItem);
		if (item_member(newItem)->parent)
			item_member(newItem)->parent->removeChild(newItem);
		item_member(newItem)->attach(this);
	}
	else
	{
		member.items.remove(item);
	}

	this->emit(Signal_ItemRemoved, item);
	if (newItem)
	{
		this->emit(Signal_ItemInserted, newItem);
	}

	member.dirty = true;
	this->fresh();
	return true;
}

int BTreeWidget::itemCount() const
{
	return member.items.size();
}
BTreeItem* BTreeWidget::item(int index)
{
	return member.items(index);
}
const BTreeItem* BTreeWidget::item(int index) const
{
	return member.items(index);
}

BTreeItem* BTreeWidget::item(const BString& text)
{
	for (int i = 0; i < member.items.size(); i++)
	{
		BTreeItem* item = member.items[i];
		if (item->text() == text)
			return item;
	}
	return 0;
}
const BTreeItem* BTreeWidget::item(const BString& text) const
{
	for (int i = 0; i < member.items.size(); i++)
	{
		const BTreeItem* item = member.items[i];
		if (item->text() == text)
			return item;
	}
	return 0;
}

BTreeItem* BTreeWidget::itemOfText(const BString& text)
{
	for (int i = 0; i < member.items.size(); i++)
	{
		BTreeItem* item = member.items[i];
		BTreeItem* result = item->findByText(text);
		if (result)
			return result;
	}
	return 0;
}
const BTreeItem* BTreeWidget::itemOfText(const BString& text) const
{
	for (int i = 0; i < member.items.size(); i++)
	{
		BTreeItem* item = member.items[i];
		BTreeItem* result = item->findByText(text);
		if (result)
			return result;
	}
	return 0;
}

BTreeItem* BTreeWidget::itemOfAsset(const BValue& value)
{
	for (int i = 0; i < member.items.size(); i++)
	{
		BTreeItem* item = member.items[i];
		BTreeItem* result = item->findByAsset(value);
		if (result)
			return result;
	}
	return 0;
}
const BTreeItem* BTreeWidget::itemOfAsset(const BValue& value) const
{
	for (int i = 0; i < member.items.size(); i++)
	{
		BTreeItem* item = member.items[i];
		BTreeItem* result = item->findByAsset(value);
		if (result)
			return result;
	}
	return 0;
}

BTreeItem* BTreeWidget::itemAt(const BPoint& point)
{
	BRect crect = this->centerRect();
	if (!crect.contain(point))
		return 0;
	BPoint offset = this->offset();
	for (int i = 0; i < member.visualItems.size(); i++)
	{
		BTreeItem* item = member.visualItems[i];
		if (!item_member(item)->visible)
			continue;
		BRect rect(item_member(item)->pos + offset, item_member(item)->size);
		rect.left() = crect.left();
		rect.right() = crect.right();
		if (rect.contain(point))
			return item;
	}
	return 0;
}
const BTreeItem* BTreeWidget::itemAt(const BPoint& point) const
{
	BRect crect = this->centerRect();
	if (!crect.contain(point))
		return 0;
	BPoint offset = this->offset();
	for (int i = 0; i < member.visualItems.size(); i++)
	{
		const BTreeItem* item = member.visualItems[i];
		if (!item_member(item)->visible)
			continue;
		BRect rect(item_member(item)->pos + offset, item_member(item)->size);
		rect.left() = crect.left();
		rect.right() = crect.right();
		if (rect.contain(point))
			return item;
	}
	return 0;
}

BTreeItem* BTreeWidget::itemAbove(const BPoint& point)
{
	BRect crect = this->centerRect();
	if (!crect.contain(point))
		return 0;
	BTreeItem* prevItem = 0;
	BPoint offset = this->offset();
	for (int i = 0; i < member.visualItems.size(); i++)
	{
		BTreeItem* item = member.visualItems[i];
		if (!item_member(item)->visible)
			continue;
		BRect rect(item_member(item)->pos + offset, item_member(item)->size);
		rect.left() = crect.left();
		rect.right() = crect.right();
		if (rect.contain(point))
			return item;
		if (rect.top() > point.y())
			break;
		prevItem = item;
	}
	return prevItem;
}
const BTreeItem* BTreeWidget::itemAbove(const BPoint& point) const
{
	BRect crect = this->centerRect();
	if (!crect.contain(point))
		return 0;
	const BTreeItem* prevItem = 0;
	BPoint offset = this->offset();
	for (int i = 0; i < member.visualItems.size(); i++)
	{
		const BTreeItem* item = member.visualItems[i];
		if (!item_member(item)->visible)
			continue;
		BRect rect(item_member(item)->pos + offset, item_member(item)->size);
		rect.left() = crect.left();
		rect.right() = crect.right();
		if (rect.contain(point))
			return item;
		if (rect.top() > point.y())
			break;
		prevItem = item;
	}
	return prevItem;
}

BTreeItem* BTreeWidget::itemUnder(const BPoint& point)
{
	BRect crect = this->centerRect();
	if (!crect.contain(point))
		return 0;
	BPoint offset = this->offset();
	for (int i = 0; i < member.visualItems.size(); i++)
	{
		BTreeItem* item = member.visualItems[i];
		if (!item_member(item)->visible)
			continue;
		BRect rect(item_member(item)->pos + offset, item_member(item)->size);
		if (rect.top() > point.y())
			return item;
	}
	return 0;
}
const BTreeItem* BTreeWidget::itemUnder(const BPoint& point) const
{
	BRect crect = this->centerRect();
	if (!crect.contain(point))
		return 0;
	BPoint offset = this->offset();
	for (int i = 0; i < member.visualItems.size(); i++)
	{
		const BTreeItem* item = member.visualItems[i];
		if (!item_member(item)->visible)
			continue;
		BRect rect(item_member(item)->pos + offset, item_member(item)->size);
		if (rect.top() > point.y())
			return item;
	}
	return 0;
}

BTreeItem* BTreeWidget::create(const BString& path)
{
	int end = path.find('/');
	if (end == path.size())
	{
		BTreeItem* item = this->item(path);
		if (item == 0)
			item = this->addItem(path);
		return item;
	}
	BString text;
	path.substr(text, 0, end);
	BTreeItem* item = this->item(text);
	if (item == 0)
	{
		item = this->addItem(text);
	}
	int pos = end + 1;
	while (item && pos < path.size())
	{
		end = path.find('/', pos);
		path.substr(text, pos, end);
		BTreeItem* child = item->child(text);
		if (child == 0)
			child = item->addChild(text);
		item = child;
		pos = end + 1;
	}
	return item;
}

BTreeItem* BTreeWidget::locate(const BString& path)
{
	int end = path.find('/');
	if (end == path.size())
		return this->item(path);
	BString text;
	path.substr(text, 0, end);
	BTreeItem* item = this->item(text);
	int pos = end + 1;
	while (item && pos < path.size())
	{
		end = path.find('/', pos);
		path.substr(text, pos, end);
		item = item->child(text);
		pos = end + 1;
	}
	return item;
}
const BTreeItem* BTreeWidget::locate(const BString& path) const
{
	int end = path.find('/');
	if (end == path.size())
		return this->item(path);
	BString text;
	path.substr(text, 0, end);
	const BTreeItem* item = this->item(text);
	int pos = end + 1;
	while (item && pos < path.size())
	{
		end = path.find('/', pos);
		path.substr(text, pos, end);
		item = item->child(text);
		pos = end + 1;
	}
	return item;
}

bool BTreeWidget::setSelection(BTreeItem* selectedItem)
{
	bool selectionChanged = false;
	for (int i = 0; i < member.selectedItems.size(); i++)
	{
		BTreeItem* item = member.selectedItems[i];
		if (selectedItem != item)
		{
			item_member(item)->selected = false;
			member.selectedItems.remove(i--);
			emit(Signal_ItemSelected, item);
			selectionChanged = true;
		}
	}
	if (!member.selectedItems.contain(selectedItem))
	{
		item_member(selectedItem)->selected = true;
		member.selectedItems.append(selectedItem);
		emit(Signal_ItemSelected, selectedItem);
		selectionChanged = true;
	}
	if (selectionChanged)
	{
		emit(Signal_SelectionChanged, member.selectedItems.size());
		this->fresh();
		return true;
	}
	return false;
}
bool BTreeWidget::setSelection(const BTreeItemArray& selection)
{
	bool selectionChanged = false;
	for (int i = 0; i< member.selectedItems.size(); i++)
	{
		BTreeItem* item = member.selectedItems[i];
		if (!selection.contain(item))
		{
			item_member(item)->selected = false;
			member.selectedItems.remove(i--);
			emit(Signal_ItemSelected, item);
			selectionChanged = true;
		}
	}
	for (int i = 0; i < selection.size(); i++)
	{
		BTreeItem* item = selection[i];
		if (!member.selectedItems.contain(item))
		{
			item_member(item)->selected = true;
			member.selectedItems.append(item);
			emit(Signal_ItemSelected, item);
			selectionChanged = true;
		}
	}
	member.selectedItems = selection;
	if (selectionChanged)
	{
		emit(Signal_SelectionChanged, member.selectedItems.size());
		this->fresh();
		return true;
	}
	return false;
}
const BTreeItemArray& BTreeWidget::selection() const
{
	return member.selectedItems;
}

bool BTreeWidget::setItemSelected(BTreeItem* item, bool selected)
{
	if (!item)
	{
		return false;
	}
	if (selected)
	{
		if (member.selectMode & Select_Multiple)
		{
			if (!member.selectedItems.contain(item))
			{
				member.selectedItems.append(item);
				item_member(item)->selected = true;
				emit(Signal_ItemSelected, item);
				emit(Signal_SelectionChanged, member.selectedItems.size());
				this->fresh();
				return true;
			}
		}
		else
		{
			for (int i = 0; i < member.selectedItems.size(); i++)
			{
				BTreeItem* selectedItem = member.selectedItems[i];
				if (selectedItem != item)
				{
					member.selectedItems.remove(i--);
					item_member(selectedItem)->selected = false;
					emit(Signal_ItemSelected, selectedItem);
				}
			}
			if (!member.selectedItems.contain(item))
			{
				member.selectedItems.append(item);
				item_member(item)->selected = true;
				emit(Signal_ItemSelected, item);
			}
			emit(Signal_SelectionChanged, member.selectedItems.size());
			this->fresh();
		}
	}
	else
	{
		if (member.selectMode & Select_Multiple)
		{
			if (member.selectedItems.contain(item))
			{
				member.selectedItems.remove(item);
				item_member(item)->selected = false;
				emit(Signal_ItemSelected, item);
				emit(Signal_SelectionChanged, member.selectedItems.size());
				this->fresh();
				return true;
			}
		}
		else
		{
			for (int i = 0; i < member.selectedItems.size(); i++)
			{
				BTreeItem* selectedItem = member.selectedItems[i];
				if (selectedItem != item)
				{
					member.selectedItems.remove(i--);
					item_member(selectedItem)->selected = false;
					emit(Signal_ItemSelected, selectedItem);
				}
			}
			if (member.selectedItems.remove(item))
			{
				item_member(item)->selected = false;
				emit(Signal_ItemSelected, item);
			}
			emit(Signal_SelectionChanged, member.selectedItems.size());
			this->fresh();
		}
	}
	return true;
}
bool BTreeWidget::clearSelection()
{
	if (member.selectedItems.empty())
		return false;
	while (BTreeItem* item = member.selectedItems.last())
	{
		member.selectedItems -= item;
		item_member(item)->selected = false;
		emit(Signal_ItemSelected, item);
	}
	emit(Signal_SelectionChanged, member.selectedItems.size());
	this->fresh();
	return true;
}

int BTreeWidget::selectedItemCount() const
{
	return member.selectedItems.size();
}
BTreeItem* BTreeWidget::selectedItem(int index)
{
	return member.selectedItems(index);
}
const BTreeItem* BTreeWidget::selectedItem(int index) const
{
	return member.selectedItems(index);
}

BTreeItem* BTreeWidget::hoveredItem()
{
	return member.hoveredItem;
}
const BTreeItem* BTreeWidget::hoveredItem() const
{
	return member.hoveredItem;
}

bool BTreeWidget::itemVisual(BTreeItem* item) const
{
	return member.visualItems.contain(item);
}
const BTreeItemArray& BTreeWidget::visualItems() const
{
	return member.visualItems;
}

bool BTreeWidget::scrollToItem(BTreeItem* item, Align align)
{
	if (!item || item_member(item)->tree != this)
		return false;
	BTreeItem* parent = item->parent();
	while (parent)
	{
		this->expand(parent);
		parent = parent->parent();
	}
	if (member.dirty)
	{
		this->flush();
	}
	BRect crect = this->centerRect();
	BRect area = this->area();
	if (item)
	{
		BRect rect0 = item_member(item)->ia_textArea;
		rect0 += item_member(item)->pos;
		rect0 += area.pos();
		BRect rect1 = crect.wrap(rect0);
		if (align)
		{
			rect1 = crect.align(align, rect0.size());
		}
		BPoint offset = rect1.pos() - rect0.pos();
		area.move(offset);
	}
	else
	{
		area = crect.align(align, area.size());
	}
	this->setArea(area);
	return true;
}

bool BTreeWidget::sortItems(int mode)
{
	if (mode == 0)
		return false;

	bool changed = false;
	for (int i = 0; i < member.items.size(); i++)
	{
		int select = i;
		BTreeItem* itemHit = member.items[i];
		if (!itemHit)
			continue;
		for (int r = i + 1; r < member.items.size(); r++)
		{
			BTreeItem* item = member.items[r];
			if (!item)
				continue;
			if (mode < 0 && itemHit->text() > item->text())
			{
				itemHit = item;
				select = r;
			}
			if (mode > 0 && itemHit->text() < item->text())
			{
				itemHit = item;
				select = r;
			}
		}
		if (select != i)
		{
			member.items.move(select, i);
			changed = true;
		}
	}
	if (!changed)
		return false;

	for (int i = 0; i < member.items.size(); i++)
	{
		BTreeItem* item = member.items[i];
		member.dirtyItem(item);
	}

	member.dirty = true;
	this->fresh();
	return true;
}
bool BTreeWidget::sortItems(BTreeItem* item, int mode)
{
	if (mode == 0)
		return false;
	if (!item)
		return false;
	if (item_member(item)->tree != this)
		return false;

	bool changed = false;
	BArray<BTreeItemHolder>& children = item_member(item)->children;
	for (int i = 0; i < children.size(); i++)
	{
		int select = i;
		BTreeItem* itemHit = children[i];
		if (!itemHit)
			continue;
		for (int r = i + 1; r < children.size(); r++)
		{
			BTreeItem* item = children[r];
			if (!item)
				continue;
			if (mode < 0 && itemHit->text() > item->text())
			{
				itemHit = item;
				select = r;
			}
			if (mode > 0 && itemHit->text() < item->text())
			{
				itemHit = item;
				select = r;
			}
		}
		if (select != i)
		{
			children.move(select, i);
			changed = true;
		}
	}
	if (!changed)
		return false;

	member.dirtyItem(item);
	member.dirty = true;
	this->fresh();
	return true;
}

const BString& BTreeWidget::realTips() const
{
	if (member.hoveredItem)
	{
		return member.hoveredItem->tips();
	}
	return BScrollArea::realTips();
}

bool BTreeWidget::query(const BString& text, BValue& value) const
{
	if (text == "visual-items")
	{
		BTreeItemArray& items = value.fill<BTreeItemArray>();
		items = member.visualItems;
		return true;
	}
	if (text == "hovered-item")
	{
		value = member.hoveredItem;
		return true;
	}
	return BScrollArea::query(text, value);
}

void BTreeWidget::scrolling(Orientation orientation)
{
	member.dirtyVisual = true;
	this->fresh();
	BScrollArea::scrolling(orientation);
}

void BTreeWidget::styleEvent(const BEvent& event)
{
	BScrollArea::styleEvent(event);
	const BStyle* style = event.value();

	style_member(style)->assign(Value_Indent, member.indent);
	style_member(style)->assign(Value_Arrow_Size, member.arrowSize);
	style_member(style)->assign(Value_Arrow_Align, member.arrowAlign);
	style_member(style)->assign(Value_ItemSpacing, member.itemSpacing);

	BIcon* expandIcon = style->icon(Icon_Expand);
	if (expandIcon)
		member.expandIcon = expandIcon;

	BIcon* shrinkIcon = style->icon(Icon_Shrink);
	if (shrinkIcon)
		member.shrinkIcon = shrinkIcon;

	member.itemStyle = 0;
	if (const BStyle* itemStyle = style->annex("item"))
	{
		member.itemStyle = itemStyle;
		style_member(itemStyle)->assign(Value_Align, member.itemAlign);
		style_member(itemStyle)->assign(Value_Width, member.itemSize.width());
		style_member(itemStyle)->assign(Value_Height, member.itemSize.height());
		style_member(itemStyle)->assign(Value_ItemSpacing, member.itemSpacing);
	}
	for (int i = 0; i < member.items.size(); i++)
	{
		BTreeItem* item = member.items[i];
		member.dirtyItem(item);
	}
	member.dirty = true;
}
void BTreeWidget::freshEvent(const BEvent& event)
{
	if (member.dirty)
	{
		member.dirty = false;
		member.dirtyVisual = true;
		member.freshArea();
	}
	if (member.dirtyVisual)
	{
		member.dirtyVisual = false;
		member.freshVisualItems();
	}
	BScrollArea::freshEvent(event);
}
void BTreeWidget::paintEvent(const BEvent& event)
{
	BScrollArea::paintEvent(event);

	const BRect& crect = this->centerRect();
	const BPoint& offset = this->offset();

	BPainter painter(this);
	painter.setClip(crect);
	State state = painter.state();
	for (int i = 0; i < member.visualItems.size(); i++)
	{
		const BTreeItem* item = member.visualItems[i];
		State itemState = state;
		if (item_member(item)->checked)
			itemState = State_Checked;
		if (!item->enabled())
			itemState = State_Disable;
		if (member.hoveredItem == item)
		{
			if (member.pressed)
				itemState |= State_Pressed;
			else
				itemState |= State_Hovered;
		}
		else if (item->selected())
		{
			itemState |= State_Selected;
		}

		painter.pushMatrix();
		painter.translate(item_member(item)->pos + offset);
		painter.setStyle(item_member(item)->realStyle);
		item_member(item)->drawBackground(painter, itemState);
		if (item_member(item)->margin.valid())
			item_member(item)->drawMargin(painter, itemState);
		if (item_member(item)->border > 0)
			item_member(item)->drawBorder(painter, itemState);
		item_member(item)->drawContent(painter, itemState);
		painter.popMatrix();

		if (item->childCount() && member.arrowVisible)
		{
			State arrowState = state;
			if (member.hoveredItem == item)
			{
				if (member.hoveredArrow)
				{
					if (member.pressed)
						arrowState |= State_Pressed;
					else
						arrowState |= State_Hovered;
				}
			}
			if (painter.setColor(Color_Arrow, arrowState))
			{
				if (item->expanded())
				{
					if (member.expandIcon)
						painter.drawImage(item_member(item)->arrowRect, member.expandIcon->image(arrowState));
					else
						painter.drawGraph(item_member(item)->arrowRect, Graph_Arrow_Down_Fill);
				}
				else
				{
					if (member.shrinkIcon)
						painter.drawImage(item_member(item)->arrowRect, member.shrinkIcon->image(arrowState));
					else
						painter.drawGraph(item_member(item)->arrowRect, Graph_Arrow_Right_Fill);
				}
			}
		}
	}
	painter.setStyle(0);
	painter.setClip(this->size());
}

void BTreeWidget::mouseEnterEvent(const BMouseEvent& mouseEvent)
{
	if (member.hoveredItem)
	{
		member.hoveredItem = 0;
		this->fresh();
	}
	BScrollArea::mouseEnterEvent(mouseEvent);
}
void BTreeWidget::mouseLeaveEvent(const BMouseEvent& mouseEvent)
{
	if (member.hoveredItem)
	{
		member.hoveredItem = 0;
		this->fresh();
	}
	BScrollArea::mouseLeaveEvent(mouseEvent);
}

void BTreeWidget::mousePressEvent(const BMouseEvent& mouseEvent)
{
	if (mouseEvent.button() == Button_Left)
	{
		member.pressed = true;
		this->fresh();
	}
	BScrollArea::mousePressEvent(mouseEvent);
}
void BTreeWidget::mouseReleaseEvent(const BMouseEvent& mouseEvent)
{
	if (mouseEvent.button() == Button_Left)
	{
		member.pressed = false;
		this->fresh();
	}
	BScrollArea::mouseReleaseEvent(mouseEvent);
}
void BTreeWidget::mouseMoveEvent(const BMouseEvent& mouseEvent)
{
	const BPoint& pos = mouseEvent.pos();
	BTreeItem* hoveredItem = this->itemAt(pos);
	if (member.hoveredItem != hoveredItem)
	{
		member.hoveredItem = hoveredItem;
		emit(Signal_ItemHovered, hoveredItem);
		this->fresh();
	}
	if (hoveredItem)
	{
		bool hoveredArrow = item_member(hoveredItem)->arrowArea.contain(pos);
		if (member.hoveredArrow != hoveredArrow)
		{
			member.hoveredArrow = hoveredArrow;
			this->fresh();
		}
	}
	else
	{
		if (member.hoveredArrow)
		{
			member.hoveredArrow = false;
			this->fresh();
		}
	}
	BScrollArea::mouseMoveEvent(mouseEvent);
}

void BTreeWidget::mouseClickEvent(const BMouseEvent& mouseEvent)
{
	if (mouseEvent.button() == Button_Left)
	{
		if (area_member(this)->hoverTitle)
		{
			//this->fresh();
		}
		else if (member.hoveredArrow)
		{
			if (member.hoveredItem->expanded())
				this->shrink(member.hoveredItem);
			else
				this->expand(member.hoveredItem);
			if (member.hoveredItem->childCount() > 0)
			{
				this->fresh();
			}
		}
		else
		{
			if (member.selectMode & Select_Single)
			{
				BTreeItem* item = member.hoveredItem;
				if (item)
				{
					bool selectionChanged = false;
					for (int i = 0; i < member.selectedItems.size(); i++)
					{
						if (member.selectedItems[i] != item)
						{
							BTreeItem* temp = member.selectedItems[i];
							member.selectedItems.remove(i--);
							item_member(temp)->selected = false;
							emit(Signal_ItemSelected, temp);
							selectionChanged = true;
						}
					}
					if (member.selectedItems.empty())
					{
						member.selectedItems.append(item);
						item_member(item)->selected = true;
						emit(Signal_ItemSelected, item);
						selectionChanged = true;
					}
					if (selectionChanged)
					{
						emit(Signal_SelectionChanged, member.selectedItems.size());
						this->fresh();
					}
				}
				else
				{
					clearSelection();
				}
			}
			if (member.selectMode & Select_Multiple)
			{
				BTreeItem* item = member.hoveredItem;
				if (item == 0)
				{
					if (!mouseEvent.keyState(Key_Ctrl) && !mouseEvent.keyState(Key_Shift))
					{
						clearSelection();
					}
				}
				else if (member.selectMode & Select_Multiple && mouseEvent.keyState(Key_Ctrl))
				{
					bool selected = !item_member(item)->selected;
					setItemSelected(item, selected);
				}
				else if (member.selectMode & Select_Continuous && mouseEvent.keyState(Key_Shift))
				{
					if (member.selectedItems.empty())
					{
						setItemSelected(item, true);
					}
					else if (member.selectedItems.first() != item)
					{
						bool selectionChanged = false;
						BTreeItemArray selection;
						BTreeItem* firstItem = member.selectedItems.first();
						if (firstItem->rect().top() < item->rect().top())
						{
							member.collectNextItems(firstItem, item, selection);
						}
						else
						{
							member.collectPrevItems(firstItem, item, selection);
						}
						this->setSelection(selection);
					}
				}
				else
				{
					bool selectionChanged = false;
					for (int i = 0; i < member.selectedItems.size(); i++)
					{
						if (member.selectedItems[i] != item)
						{
							BTreeItem* temp = member.selectedItems[i];
							member.selectedItems.remove(i--);
							item_member(temp)->selected = false;
							emit(Signal_ItemSelected, temp);
							selectionChanged = true;
						}
					}
					if (item && member.selectedItems.empty())
					{
						member.selectedItems.append(item);
						item_member(item)->selected = true;
						emit(Signal_ItemSelected, item);
						selectionChanged = true;
					}
					if (selectionChanged)
					{
						emit(Signal_SelectionChanged, member.selectedItems.size());
						this->fresh();
					}
				}
			}
		}
	}
	if (!member.hoveredArrow)
	{
		if (mouseEvent.button() == Button_Left)
		{
			emit(Signal_ItemClicked, member.hoveredItem);
		}
		if (mouseEvent.button() == Button_Right)
		{
			emit(Signal_ItemRightClicked, member.hoveredItem);
		}
	}
	BScrollArea::mouseClickEvent(mouseEvent);
}
void BTreeWidget::mouseDoubleClickEvent(const BMouseEvent& mouseEvent)
{
	if (mouseEvent.button() == Button_Left)
	{
		if (!member.hoveredArrow)
		{
			if (member.hoveredItem)
			{
				emit(Signal_ItemDoubleClicked, member.hoveredItem);
			}
		}
	}
	BScrollArea::mouseDoubleClickEvent(mouseEvent);
}
